{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "# os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"1\"\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 加载数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1778030, 12) (1778030, 1) (508012, 12) (508012, 1) (254005, 12) (254005, 1)\n"
     ]
    }
   ],
   "source": [
    "x_train = np.load('E:/IDS/alldata/12/train/data.npy')\n",
    "y_train = np.load('E:/IDS/alldata/12/train/label_2.npy')\n",
    "\n",
    "x_test = np.load('E:/IDS/alldata/12/test/data.npy')\n",
    "y_test = np.load('E:/IDS/alldata/12/test/label_2.npy')\n",
    "\n",
    "x_val = np.load('E:/IDS/alldata/12/val/data.npy')\n",
    "y_val = np.load('E:/IDS/alldata/12/val/label_2.npy')\n",
    "\n",
    "print(x_train.shape,y_train.shape,x_test.shape,y_test.shape,x_val.shape,y_val.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:526: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:527: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:528: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:529: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:530: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
      "f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\dtypes.py:535: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
      "  np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
     ]
    }
   ],
   "source": [
    "x_train = np.expand_dims(x_train,2)\n",
    "x_test = np.expand_dims(x_test,2)\n",
    "x_val = np.expand_dims(x_val,2)\n",
    "\n",
    "from keras.utils import to_categorical\n",
    "y_train = to_categorical(y_train)\n",
    "y_test = to_categorical(y_test)\n",
    "y_val = to_categorical(y_val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(1778030, 2)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_train.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.layers import Conv1D,MaxPooling1D,Dense,Dropout,Input,Flatten,GlobalAveragePooling1D\n",
    "from keras.layers.normalization import BatchNormalization\n",
    "from keras.models import Model\n",
    "from keras.optimizers import Nadam\n",
    "from keras import initializers\n",
    "from keras import regularizers\n",
    "np.random.seed(4)\n",
    "import pickle\n",
    "import math\n",
    "from keras.callbacks import LearningRateScheduler, ModelCheckpoint\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "n_obs,feature, depth = x_train.shape\n",
    "batch_size = 256\n",
    "def build_model():\n",
    "    input_singal = Input(shape=(feature,depth))\n",
    "    x = Conv1D(32,3,activation='relu',padding='same',kernel_initializer='he_uniform')(input_singal)\n",
    "    #padding='same'填充后输出的宽度和高度与输入相同\n",
    "    x = Conv1D(32,3,activation='relu',padding='same',kernel_initializer='he_uniform')(x)\n",
    "    x = MaxPooling1D(pool_size=2,strides=2)(x)#对特征图进行下采样，将特征图下采样2倍\n",
    "    x = Dropout(0.2)(x)\n",
    "    x = BatchNormalization()(x)\n",
    "    \n",
    "    x = Conv1D(64,3,activation='relu',padding='same',kernel_initializer='he_uniform')(x)\n",
    "    x = Conv1D(64,3,activation='relu',padding='same',kernel_initializer='he_uniform')(x) \n",
    "    x = MaxPooling1D(pool_size=2,strides=2)(x)\n",
    "    x = Dropout(0.2)(x)\n",
    "    x = BatchNormalization()(x)    \n",
    "    \n",
    "    x = Flatten()(x)\n",
    "    x = Dense(32,activation='relu')(x)\n",
    "    x = Dense(2,activation='softmax')(x)\n",
    "    model = Model(inputs=input_singal,outputs=x)\n",
    "    \n",
    "    return model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\framework\\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Colocations handled automatically by placer.\n",
      "WARNING:tensorflow:From f:\\anaconda\\envs\\py37\\lib\\site-packages\\keras\\backend\\tensorflow_backend.py:3445: calling dropout (from tensorflow.python.ops.nn_ops) with keep_prob is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Please use `rate` instead of `keep_prob`. Rate should be set to `rate = 1 - keep_prob`.\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         (None, 12, 1)             0         \n",
      "_________________________________________________________________\n",
      "conv1d_1 (Conv1D)            (None, 12, 32)            128       \n",
      "_________________________________________________________________\n",
      "conv1d_2 (Conv1D)            (None, 12, 32)            3104      \n",
      "_________________________________________________________________\n",
      "max_pooling1d_1 (MaxPooling1 (None, 6, 32)             0         \n",
      "_________________________________________________________________\n",
      "dropout_1 (Dropout)          (None, 6, 32)             0         \n",
      "_________________________________________________________________\n",
      "batch_normalization_1 (Batch (None, 6, 32)             128       \n",
      "_________________________________________________________________\n",
      "conv1d_3 (Conv1D)            (None, 6, 64)             6208      \n",
      "_________________________________________________________________\n",
      "conv1d_4 (Conv1D)            (None, 6, 64)             12352     \n",
      "_________________________________________________________________\n",
      "max_pooling1d_2 (MaxPooling1 (None, 3, 64)             0         \n",
      "_________________________________________________________________\n",
      "dropout_2 (Dropout)          (None, 3, 64)             0         \n",
      "_________________________________________________________________\n",
      "batch_normalization_2 (Batch (None, 3, 64)             256       \n",
      "_________________________________________________________________\n",
      "flatten_1 (Flatten)          (None, 192)               0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 32)                6176      \n",
      "_________________________________________________________________\n",
      "dense_2 (Dense)              (None, 2)                 66        \n",
      "=================================================================\n",
      "Total params: 28,418\n",
      "Trainable params: 28,226\n",
      "Non-trainable params: 192\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model =  build_model()\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From f:\\anaconda\\envs\\py37\\lib\\site-packages\\tensorflow\\python\\ops\\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.cast instead.\n",
      "Train on 1778030 samples, validate on 254005 samples\n",
      "Epoch 1/100\n",
      " - 51s - loss: 0.0262 - acc: 0.9863 - val_loss: 0.0229 - val_acc: 0.9884\n",
      "Epoch 2/100\n",
      " - 50s - loss: 0.0223 - acc: 0.9877 - val_loss: 0.0212 - val_acc: 0.9879\n",
      "Epoch 3/100\n",
      " - 49s - loss: 0.0216 - acc: 0.9880 - val_loss: 0.0215 - val_acc: 0.9876\n",
      "Epoch 4/100\n",
      " - 49s - loss: 0.0213 - acc: 0.9881 - val_loss: 0.0206 - val_acc: 0.9888\n",
      "Epoch 5/100\n",
      " - 49s - loss: 0.0211 - acc: 0.9882 - val_loss: 0.0205 - val_acc: 0.9881\n",
      "Epoch 6/100\n",
      " - 49s - loss: 0.0209 - acc: 0.9882 - val_loss: 0.0205 - val_acc: 0.9893\n",
      "Epoch 7/100\n",
      " - 49s - loss: 0.0207 - acc: 0.9883 - val_loss: 0.0199 - val_acc: 0.9894\n",
      "Epoch 8/100\n",
      " - 49s - loss: 0.0205 - acc: 0.9884 - val_loss: 0.0202 - val_acc: 0.9892\n",
      "Epoch 9/100\n",
      " - 48s - loss: 0.0204 - acc: 0.9884 - val_loss: 0.0207 - val_acc: 0.9883\n",
      "Epoch 10/100\n",
      " - 48s - loss: 0.0205 - acc: 0.9885 - val_loss: 0.0200 - val_acc: 0.9893\n",
      "Epoch 11/100\n",
      " - 48s - loss: 0.0199 - acc: 0.9889 - val_loss: 0.0188 - val_acc: 0.9898\n",
      "Epoch 12/100\n",
      " - 48s - loss: 0.0197 - acc: 0.9891 - val_loss: 0.0188 - val_acc: 0.9895\n",
      "Epoch 13/100\n",
      " - 48s - loss: 0.0197 - acc: 0.9890 - val_loss: 0.0185 - val_acc: 0.9899\n",
      "Epoch 14/100\n",
      " - 48s - loss: 0.0194 - acc: 0.9895 - val_loss: 0.0188 - val_acc: 0.9902\n",
      "Epoch 15/100\n",
      " - 48s - loss: 0.0194 - acc: 0.9894 - val_loss: 0.0197 - val_acc: 0.9885\n",
      "Epoch 16/100\n",
      " - 48s - loss: 0.0192 - acc: 0.9896 - val_loss: 0.0185 - val_acc: 0.9901\n",
      "Epoch 17/100\n",
      " - 48s - loss: 0.0192 - acc: 0.9896 - val_loss: 0.0184 - val_acc: 0.9904\n",
      "Epoch 18/100\n",
      " - 48s - loss: 0.0190 - acc: 0.9898 - val_loss: 0.0186 - val_acc: 0.9903\n",
      "Epoch 19/100\n",
      " - 48s - loss: 0.0190 - acc: 0.9899 - val_loss: 0.0184 - val_acc: 0.9902\n",
      "Epoch 20/100\n",
      " - 48s - loss: 0.0190 - acc: 0.9900 - val_loss: 0.0182 - val_acc: 0.9904\n",
      "Epoch 21/100\n",
      " - 48s - loss: 0.0188 - acc: 0.9901 - val_loss: 0.0181 - val_acc: 0.9903\n",
      "Epoch 22/100\n",
      " - 48s - loss: 0.0190 - acc: 0.9897 - val_loss: 0.0185 - val_acc: 0.9905\n",
      "Epoch 23/100\n",
      " - 48s - loss: 0.0188 - acc: 0.9900 - val_loss: 0.0182 - val_acc: 0.9902\n",
      "Epoch 24/100\n",
      " - 48s - loss: 0.0190 - acc: 0.9897 - val_loss: 0.0190 - val_acc: 0.9899\n",
      "Epoch 25/100\n",
      " - 48s - loss: 0.0188 - acc: 0.9899 - val_loss: 0.0185 - val_acc: 0.9905\n",
      "Epoch 26/100\n",
      " - 48s - loss: 0.0187 - acc: 0.9900 - val_loss: 0.0180 - val_acc: 0.9901\n",
      "Epoch 27/100\n",
      " - 48s - loss: 0.0186 - acc: 0.9901 - val_loss: 0.0180 - val_acc: 0.9906\n",
      "Epoch 28/100\n",
      " - 48s - loss: 0.0187 - acc: 0.9901 - val_loss: 0.0182 - val_acc: 0.9906\n",
      "Epoch 29/100\n",
      " - 48s - loss: 0.0187 - acc: 0.9901 - val_loss: 0.0180 - val_acc: 0.9905\n",
      "Epoch 30/100\n",
      " - 48s - loss: 0.0187 - acc: 0.9900 - val_loss: 0.0180 - val_acc: 0.9906\n",
      "Epoch 31/100\n",
      " - 48s - loss: 0.0186 - acc: 0.9900 - val_loss: 0.0192 - val_acc: 0.9898\n",
      "Epoch 32/100\n",
      " - 48s - loss: 0.0186 - acc: 0.9901 - val_loss: 0.0180 - val_acc: 0.9905\n",
      "Epoch 33/100\n",
      " - 48s - loss: 0.0184 - acc: 0.9903 - val_loss: 0.0181 - val_acc: 0.9904\n",
      "Epoch 34/100\n",
      " - 48s - loss: 0.0184 - acc: 0.9903 - val_loss: 0.0181 - val_acc: 0.9905\n",
      "Epoch 35/100\n",
      " - 49s - loss: 0.0184 - acc: 0.9902 - val_loss: 0.0184 - val_acc: 0.9905\n",
      "Epoch 36/100\n",
      " - 48s - loss: 0.0185 - acc: 0.9902 - val_loss: 0.0181 - val_acc: 0.9904\n",
      "Epoch 37/100\n",
      " - 49s - loss: 0.0178 - acc: 0.9905 - val_loss: 0.0174 - val_acc: 0.9907\n",
      "Epoch 38/100\n",
      " - 48s - loss: 0.0177 - acc: 0.9905 - val_loss: 0.0173 - val_acc: 0.9907\n",
      "Epoch 39/100\n",
      " - 48s - loss: 0.0176 - acc: 0.9905 - val_loss: 0.0173 - val_acc: 0.9908\n",
      "Epoch 40/100\n",
      " - 48s - loss: 0.0176 - acc: 0.9906 - val_loss: 0.0172 - val_acc: 0.9908\n",
      "Epoch 41/100\n",
      " - 48s - loss: 0.0175 - acc: 0.9906 - val_loss: 0.0172 - val_acc: 0.9908\n",
      "Epoch 42/100\n",
      " - 49s - loss: 0.0175 - acc: 0.9907 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 43/100\n",
      " - 48s - loss: 0.0175 - acc: 0.9906 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 44/100\n",
      " - 49s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 45/100\n",
      " - 48s - loss: 0.0175 - acc: 0.9907 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 46/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9906 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 47/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0171 - val_acc: 0.9909\n",
      "Epoch 48/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 49/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0171 - val_acc: 0.9910\n",
      "Epoch 50/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0171 - val_acc: 0.9910\n",
      "Epoch 51/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0171 - val_acc: 0.9910\n",
      "Epoch 52/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0172 - val_acc: 0.9909\n",
      "Epoch 53/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0171 - val_acc: 0.9909\n",
      "Epoch 54/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0171 - val_acc: 0.9909\n",
      "Epoch 55/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9907 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 56/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 57/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 58/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0171 - val_acc: 0.9911\n",
      "Epoch 59/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 60/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 61/100\n",
      " - 48s - loss: 0.0174 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9910\n",
      "Epoch 62/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 63/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0172 - val_acc: 0.9911\n",
      "Epoch 64/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9910\n",
      "Epoch 65/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9908 - val_loss: 0.0170 - val_acc: 0.9910\n",
      "Epoch 66/100\n",
      " - 48s - loss: 0.0173 - acc: 0.9909 - val_loss: 0.0170 - val_acc: 0.9912\n",
      "Epoch 67/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 68/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 69/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 70/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 71/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 72/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 73/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 74/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 75/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9912\n",
      "Epoch 76/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 77/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 78/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 79/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 80/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 81/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 82/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0170 - val_acc: 0.9911\n",
      "Epoch 83/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 84/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 85/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 86/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 87/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 88/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 89/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 90/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 91/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 92/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 93/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 94/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 95/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 96/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 97/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9908 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 98/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 99/100\n",
      " - 48s - loss: 0.0171 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "Epoch 100/100\n",
      " - 48s - loss: 0.0172 - acc: 0.9909 - val_loss: 0.0169 - val_acc: 0.9911\n",
      "train_time: 4820.229252099991\n"
     ]
    }
   ],
   "source": [
    "import keras\n",
    "import time\n",
    "time_start = time.time()\n",
    "\n",
    "reduce_lr = keras.callbacks.ReduceLROnPlateau(moniter='val_loss',\n",
    "                                              factor=0.1,\n",
    "                                              patience=10)\n",
    "nadam = Nadam(lr=0.008, beta_1=0.9, beta_2=0.999, epsilon=1e-08, schedule_decay=0.004)\n",
    "model.compile(loss = \"categorical_crossentropy\",optimizer = \"nadam\", metrics = [\"accuracy\"])#损失函数，优化器，精度\n",
    "history = model.fit(x_train, y_train, \n",
    "                    epochs=100, \n",
    "                    batch_size=batch_size, \n",
    "                    verbose=2,\n",
    "                    validation_data=(x_val, y_val),\n",
    "                    callbacks=[reduce_lr])\n",
    "time_end = time.time()\n",
    "train_time = time_end - time_start\n",
    "print(\"train_time:\",train_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.save(\"E:/IDS/alldata/12/train/2019.12.18/CNN_2_history.npy\",history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "508012/508012 [==============================] - 10s 19us/step\n",
      "test_loss =  0.017101159232763865 test_accuracy =  0.9909155689235687\n"
     ]
    }
   ],
   "source": [
    "scores = model.evaluate(x_test, y_test)\n",
    "print(\"test_loss = \", scores[0],\"test_accuracy = \", scores[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save('E:/IDS/alldata/12/train/2019.12.18/CNN_2.h5')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 测试模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "test_time: 8.304940462112427\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "time_start = time.time()\n",
    "\n",
    "y_pred_onehot  = model.predict(x_test)  #返回的是在类别上的概率分布\n",
    "y_pred_label=np.argmax(y_pred_onehot,axis=1)#概率最大的类别就是预测类别\n",
    "\n",
    "time_end = time.time()\n",
    "test_time = time_end - time_start\n",
    "print(\"test_time:\",test_time)\n",
    "\n",
    "np.savetxt(\"E:/IDS/alldata/12/train/2019.12.18/CNN_pred_2.txt\",y_pred_label)  #保存预测标签\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_true_onehot=y_test\n",
    "y_true_label=np.argmax(y_true_onehot,axis=1)\n",
    "np.savetxt(\"E:/IDS/alldata/12/train/2019.12.18/CNN_true_2.txt\",y_true_label)  #保存真实标签"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1800x1560 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# -*-coding:utf-8-*-\n",
    "from sklearn.metrics import confusion_matrix\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "labels = ['Normal','Attack']\n",
    "          \n",
    "y_true = y_true_label\n",
    "y_pred  = y_pred_label\n",
    "\n",
    "tick_marks = np.array(range(len(labels))) + 0.5\n",
    "\n",
    "def plot_confusion_matrix(cm, title='Confusion Matrix', cmap=plt.cm.binary):\n",
    "    plt.imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)  #cmap=cmap是黑白色\n",
    "    plt.title(title)\n",
    "    plt.colorbar()\n",
    "    xlocations = np.array(range(len(labels)))\n",
    "    plt.xticks(xlocations, labels, rotation=90)\n",
    "    plt.yticks(xlocations, labels)\n",
    "    plt.ylabel('True label')\n",
    "    plt.xlabel('Predicted label')\n",
    "\n",
    "\n",
    "cm = confusion_matrix(y_true, y_pred)  #cm是混淆矩阵\n",
    "np.set_printoptions(precision=2)  #保留两位小数\n",
    "cm_normalized = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]  #混淆矩阵的每个元素的值（0-1）\n",
    "\n",
    "plt.figure(figsize=(15, 13), dpi=120)\n",
    "\n",
    "ind_array = np.arange(len(labels))\n",
    "x, y = np.meshgrid(ind_array, ind_array)\n",
    "\n",
    "for x_val, y_val in zip(x.flatten(), y.flatten()):\n",
    "    c = cm_normalized[y_val][x_val]\n",
    "    if c > 0.001:\n",
    "        plt.text(x_val, y_val, \"%0.2f\" % (c,), color='red', fontsize=13, va='center', ha='center')\n",
    "# offset the tick\n",
    "plt.gca().set_xticks(tick_marks, minor=True)\n",
    "plt.gca().set_yticks(tick_marks, minor=True)\n",
    "plt.gca().xaxis.set_ticks_position('none')\n",
    "plt.gca().yaxis.set_ticks_position('none')\n",
    "plt.grid(True, which='minor', linestyle='-')\n",
    "plt.gcf().subplots_adjust(bottom=0.15)\n",
    "\n",
    "plot_confusion_matrix(cm_normalized, title='MLP_12_10_ROS Normalized confusion matrix')  #规范化的混淆矩阵\n",
    "#plt.savefig('/home/hll/IDS/alldata/cm/confusion_matrix.png', format='png')  #保存结果图\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[442197   1558]\n",
      " [  3057  61200]]\n"
     ]
    }
   ],
   "source": [
    "print(cm)  #输出混淆矩阵具体的数值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 二分类指标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "acc: 0.9909155689235687\n",
      "DR: 0.9524254166861198\n",
      "FPR: 0.003510946355534022\n",
      "recall： 0.9524254166861198\n",
      "precision: 0.9751744797476019\n",
      "f1: 0.9636657087745542\n"
     ]
    }
   ],
   "source": [
    "TP=cm[1,1]\n",
    "FP=cm[0,1]\n",
    "FN=cm[1,0]\n",
    "TN=cm[0,0]\n",
    "\n",
    "acc = (TP+TN)/(TP+TN+FP+FN)\n",
    "print(\"acc:\",acc)\n",
    "\n",
    "DR = TP/(TP+FN)  #检出率（查准率）\n",
    "print(\"DR:\",DR)\n",
    "\n",
    "FPR = FP/(FP+TN)  #假阳性率\n",
    "print(\"FPR:\",FPR)\n",
    "\n",
    "recall =TP/(TP+FN)\n",
    "print(\"recall：\",recall)  #召回率\n",
    "\n",
    "precision = TP/(TP+FP)\n",
    "print(\"precision:\",precision)\n",
    "\n",
    "f1 = (2*precision*recall)/(precision+recall)\n",
    "print(\"f1:\",f1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
